/*
  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  PARTICULAR PURPOSE.

  Copyright (c) 2009 PRO ACTIVE SAS - www.proactive-group.com
   
  Ref_15693.c
  -----------

  This is the reference applications that shows how to work with
  ISO/IEC 15693 cards.
  
  LTX 25/08/2009 : initial release

*/
#include "products/springprox/springprox.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void GetSystemInfo15693(void);
BOOL Read15693(BOOL multi, BOOL byte, BYTE start_block, BYTE nb_blocks);
BOOL Write15693(BYTE block, WORD len);

int main(int argc, char **argv)
{
  SWORD rc;
  int i = 0;
  BOOL fast = FALSE;
  TCHAR s_buffer[64];
  DWORD features;
  unsigned char snr[8];
  unsigned short len = 256;
  
  char *device = NULL;
  if (argc > 1)
    device = argv[1];

  printf("SpringCard SDK for K531/SpringProx-CF/CSB Legacy\n");
  printf("\n");
  printf("ISO 15693 reference demo\n");
  printf("-------------------------------------\n");
  printf("www.springcard.com\n\n");

  rc = SPROX_GetLibrary(s_buffer, sizeof(s_buffer));
  if (rc != MI_OK)
  {
    printf("Failed to get API version\n");
    goto done;
  }
  printf("API version : %s\n", s_buffer);
  printf("\n");

  /* Open reader */
  /* ----------- */

  rc = SPROX_ReaderOpen(device);
  if (rc != MI_OK)
  {
    printf("Reader not found\n");
    goto done;
  }

  printf("Reader found\n");
  rc = SPROX_ReaderGetDevice(s_buffer, sizeof(s_buffer));
  if (rc == MI_OK)
    printf("Reader found on %s\n", s_buffer);

  rc = SPROX_ReaderGetFirmware(s_buffer, sizeof(s_buffer));
  if (rc == MI_OK)
    printf("Reader firwmare is %s\n", s_buffer);

  rc = SPROX_ReaderGetFeatures(&features);
  if ((rc == MI_OK) && !(features & 0x00000002))
  {
    printf("Warning: this reader is not 15693-enabled\n");
    printf("         all subsequent tests will fail !\n");
  }

  printf("\n------------------------------\n");

  /* Configure reader in ISO 15693 standard mode */
  /* ------------------------------------------- */
  rc = SPROX_SetConfig(CFG_MODE_ISO_15693_STD);
  if (rc != MI_OK)
  {
    printf("Failed to configure the reader for a ISO 15693 tag\n");
    goto close;
  }

  /* RF field ON */
  SPROX_ControlRF(TRUE);

  /* Select any ISO 15693 tag in the RF field */
  /* ---------------------------------------- */
  
  printf("Put your ISO 15693 tag on the reader...\n");

  for (;;)
  {
	  rc = SPROX_Iso15693_SelectAny(fast,snr);
	  if (rc == MI_OK)
	  {
      printf("Found ISO 15693 tag in RF field\n");
      break;
	  }

	  if (i == 5)
	  {
	    fast = TRUE;
	  } else if (i == 10)
	  {
	    fast = FALSE;
	    i=0;
	  }
	  i++;
  }

  printf("Tag found: UID=");
  for (i = 0; i < 8; i++)
    printf("%02X", snr[i]);
  printf("\n");

  switch (snr[1])
  {
    case 0x04 :	/* NXP */
	  switch (snr[2])
	  {
		case 0x01 : /* ICODE SLI : 28 blocks, 4 bytes in each block */
					/* Support "Read Multiple Blocks" command       */
					printf("Tag appears to be a ICODE SLI...\n");
					GetSystemInfo15693();
					if (!Read15693(TRUE, FALSE, 0, 28)) goto tag_halt;
					if (!Write15693(5, 4)) goto tag_halt;
					break;
		case 0x03 : /* ICODE SLI-L : 8 blocks, 4 bytes in each block */
					printf("Tag appears to be a ICODE SLI-L...\n");
					GetSystemInfo15693();
					if (!Read15693(FALSE, FALSE, 0, 8)) goto tag_halt;
					if (!Write15693(5, 4)) goto tag_halt;
					break;
		case 0x02 : /* ICODE SLI-S : 40 blocks, 4 bytes in each block */
					printf("Tag appears to be a ICODE SLI-S...\n");
					GetSystemInfo15693();
					if (!Read15693(FALSE, FALSE, 0, 40)) goto tag_halt;
					if (!Write15693(5, 4)) goto tag_halt;
					break;
		default   : /* NXP card */
					printf("NXP card, unsupported by reader !\n");
					break;
	  }
	  break;

	case 0x07 :	/* Texas Instrument */
	  switch (snr[2] & 0xFE)
	  {
		case 0x00 :	/* Tag-it HF-I Plus Inlay : 64 blocks, 4 bytes in each block */
					/* Support "Read Multiple Blocks" command                    */
					printf("Tag appears to be a Tag-it HF-I Plus Inlay...\n");
					GetSystemInfo15693();
					if (!Read15693(TRUE, FALSE, 0, 64)) goto tag_halt;
					if (!Write15693(5, 4)) goto tag_halt;
					break;
		case 0x80 :	/* Tag-it HF-I Plus Chip : 64 blocks, 4 bytes in each block */
					/* Support "Read Multiple Blocks" command                   */
					printf("Tag appears to be a Tag-it HF-I Plus Chip...\n");
					GetSystemInfo15693();
					if (!Read15693(TRUE, FALSE, 0, 64)) goto tag_halt;
					if (!Write15693(5, 4)) goto tag_halt;
					break;
		case 0xC0 :	/* Tag-it HF-I Standard Chip/Inlay : 11 blocks, 4 bytes in each block (block 8 & 9 -> UID, block 10 -> AFI)*/
					printf("Tag appears to be a Tag-it HF-I Standard Chip/Inlay...\n");
					if (!Read15693(FALSE, FALSE, 0, 11)) goto tag_halt;
					if (!Write15693(5, 4)) goto tag_halt;
					break;
		case 0xC4 :	/* Tag-it HF-I Pro Chip/Inlay : 12 blocks, 4 bytes in each block (block 8 & 9 -> UID, block 10 -> AFI, block 11 -> password)*/
					printf("Tag appears to be a Tag-it HF-I Pro Chip/Inlay...\n");
					if (!Read15693(FALSE, FALSE, 0, 12)) goto tag_halt;
					if (!Write15693(5, 4)) goto tag_halt;
					break;
		default   :	/* Tag-it card */
					printf("Tag-it card, unsupported by reader !\n");
					break;
	  }
	  break;

	case 0x02 : /* STMicroelectronics card*/
	  switch ((snr[2] & 0xFC) >> 2)
	  {
		case 0x05 :	/* LRI64 : 15 blocks, 1 byte in each block (block 0 et 7 -> UID, block 8 -> AFI, block 9 -> DSFID)*/
					printf("Tag appears to be a ST LRI64...\n");
					GetSystemInfo15693();
					if (!Read15693(FALSE, FALSE, 0, 15)) goto tag_halt;
					break;
		default   :	/* ST card */
					printf("STMicroelectronics card, unsupported by reader !\n");
					break;
	  }
	break;

	case 0x16 : /* Legic card*/
				printf("Legic card, unsupported by reader !\n");
				break;

	default   : printf("Unsupported ISO 15693\n");
				break;
  }

  

tag_halt:
  /* ISO 15693 tag stop */
  /* -------------------- */
  rc = SPROX_Iso15693_Halt();
  if (rc != MI_OK)
  {
    printf("HALT failed\n");
    goto close;
  }

  /* RF field OFF */
  SPROX_ControlRF(FALSE);

close:
  /* Close the reader */
  SPROX_ReaderClose();

done:
  /* Display last error */
  if (rc == MI_OK)
  {
    printf("Done\n");
  } else
  {
    printf("%s (%d)\n", SPROX_GetErrorMessage(rc), rc);
  }
  return 0;
}

/* 
 * Get system information of ISO 15693 tag 
 * ---------------------------------------
 */
void GetSystemInfo15693(void)
{
  SWORD rc;
  int i = 0;
  unsigned char data[256];
  unsigned short len      = 256;
  unsigned short block_sz = 0;
  
  printf("\nSystem Information...\n");
  len = 256;
  rc = SPROX_Iso15693_GetSystemInformation(NULL, data, &len);
  if (rc == MI_OK) 
  {
	BYTE  ind = 0;

	printf("[OK]\n");

    if (len > 9)
    {
      printf("UID=");
	  for (i = 1; i < 9; i++)
		printf("%02X", data[i]);
        
      ind = 9;
      if (data[0] & 0x01)
      {
        printf(" DSFID=");
		printf("%02X", data[ind]);
        ind++;
      } 
                  
      if (data[0] & 0x02)
      {
        printf(" AFI=");
		printf("%02X", data[ind]);
        ind++;
      } 
                  
      if (data[0] & 0x04)
      {
        printf("\nNumber of Blocks="); 
        printf("%d",data[ind]+1);
        ind++;
        printf(" Block Size=");
		block_sz = (data[ind]+1) & 0x1F;
        printf("%d",block_sz);
        ind++;
      }
                  
      if (data[0] & 0x08)
      {
        printf("\nIC-Ref=");
		printf("%02X", data[ind]);
      }
	  printf("\n");
    }
  } else
  {
	printf("[Failed]\n");
    printf("  %s (%d)\n", SPROX_GetErrorMessage(rc), rc);
  }
}

/*
 * Read ISO 15693 tag
 * ------------------
 */
BOOL Read15693(BOOL multi, BOOL byte, BYTE start_block, BYTE nb_blocks)
{
  SWORD rc;
  BYTE block;
  BYTE rcvdata[256];
  WORD rcvlen = 256;
  WORD i;

  printf("\nReading %d blocks...\n", nb_blocks);

  if (multi) 
  { /* Read multiple blocks or bytes */
	if (byte) 
	{ /* Read multiple bytes -> Read maximun of bytes in a 15693 tag, this depends of the value of rcvlen */
	  rc = SPROX_Iso15693_ReadMultipleBytes(NULL, start_block, rcvdata, &rcvlen);
	  if (rc != MI_OK)
	  {
		printf("Read multiple bytes [Failed]\n");
		printf("  %s (%d)\n", SPROX_GetErrorMessage(rc), rc);
        return FALSE;
	  }

	} else
	{ /* Read multiple blocks -> Possible if the 15693 tag implements this function */
	  rc = SPROX_Iso15693_ReadMultipleBlocks(NULL, start_block, nb_blocks, rcvdata, &rcvlen);
	  if (rc != MI_OK)
	  {
	    printf("Read multiple blocks [Failed]\n");
		printf("  %s (%d)\n", SPROX_GetErrorMessage(rc), rc);
        return FALSE;
	  }
	}

	printf("[OK]\n");

	for (block = 0; block < nb_blocks; block++)
    {
      printf("%02d : ", block);

      for (i = 0; i < 4; i++)
      {
        printf("%02X ", rcvdata[4 * block + i]);
      }

      for (i = 0; i < 4; i++)
      {
        if (rcvdata[4 * block + i] >= ' ')
        {
		  /* RAW display of ASCII printable data */
          printf("%c", rcvdata[4 * block + i]);
        } else
        {
          printf(".");
        }
      }

      printf("\n");
    }

	/*for (i=0; i<rcvlen; i++)
	{
      printf("%02X", rcvdata[i]);
      printf("   ");
	}

	printf("\n");
	
	for (i=0; i<rcvlen; i++)
	{
      
      if (rcvdata[i] >= ' ')
        printf("%c", rcvdata[i]);
      else
        printf(".");
	}

	printf("\n");*/

  } else
  {
	for (block = start_block; block < nb_blocks; block++)
	{
	  /* Read single block */
	  rcvlen = 256;
	  rc = SPROX_Iso15693_ReadSingleBlock(NULL, block, rcvdata, &rcvlen);
	  if (rc != MI_OK)
	  {
		printf("Read read block %d [Failed]\n", block);
		printf("  %s (%d)\n", SPROX_GetErrorMessage(rc), rc);
		continue;
	  } 
       
	  printf("%02d : ", block);

      for (i=0; i<rcvlen; i++)
	  {
        printf("%02X", rcvdata[i]);
        printf("   ");
	  }
	
	  for (i=0; i<rcvlen; i++)
	  {
        /* RAW display of ASCII printable data */
        if (rcvdata[i] >= ' ')
          printf("%c", rcvdata[i]);
        else
          printf(".");
	  }

	  printf("\n");
	}
  }

  return TRUE;
}

/*
 * Write ISO 15693 tag
 * ------------------
 */
BOOL Write15693(BYTE block, WORD len)
{
  SWORD rc;
  BYTE data[256];
  WORD i;

  printf("\nWriting block %d...\n", block);

  for (i = 0; i < len; i++)
    data[i]= 'A' + i;

  rc = SPROX_Iso15693_WriteBlock(NULL, block, data, len);
  if (rc != MI_OK)
  {
    /* Erreur */
    printf("Write block %d [Failed]\n", block);
    printf("  %s (%d)\n", SPROX_GetErrorMessage(rc), rc);
    return FALSE;
  }

  printf("[OK]\n");
  return TRUE;
}